#include <stdio.h>
#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>

#define BUF_SIZE 1024
#define SZ_256    256

#define SERVICE_READY 220
#define NEED_PASSWORD 331
#define LOGIN_SUCS 230
#define CONTROL_CLOSE 221
#define PATHNAME_CREATE 257
#define PASV_MODE 227
#define NO_SUCH_FILE 550 
#define DOWN_READY   125

#define QUIT 7

struct sockaddr_in server; 		// 控制连接的socket
struct hostent* hent;      		// 服务器主机hostent*指针
char user[20] = "administrator"; // 用户名
char pass[20] = "windows";      // 密码
char filepath[250] = "windows";      // 密码   
char newfilename[250] = "hello";//NEW FILE
int data_port;              	// 数据连接端口

// 报错
static void errorReport(unsigned char err_info) 
{
    exit(1);
}

// 发送命令，参数为 socket号 、 命令标示 和 命令参数
static void sendCommand(int sock_fd, const char* cmd, const char* info) 
{
    char buf[BUF_SIZE] = {0};

    strcpy(buf, cmd);
    strcat(buf, info);
    strcat(buf, "\r\n");
    if (send(sock_fd, buf, strlen(buf), 0) < 0)
        errorReport(1);
}

// 控制连接获取服务器应答，返回应答码
static int getReplyCode(int sockfd)
{
    int r_code, bytes;
    char buf[BUF_SIZE] = {0}, nbuf[5] = {0};

    if ((bytes = read(sockfd, buf, BUF_SIZE - 2)) > 0) {
        r_code = atoi(buf);
        buf[bytes] = '\0';
    }else{
        return -1;
	}

    if (buf[3] == '-') {
        char* newline = strchr(buf, '\n');
        if (*(newline+1) == '\0') {
            while ((bytes = read(sockfd, buf, BUF_SIZE - 2)) > 0) {
                buf[bytes] = '\0';
                if (atoi(buf) == r_code)
                    break;
            }
        }
    }

    if (r_code == PASV_MODE){
        char* begin = strrchr(buf, ',')+1;
        char* end = strrchr(buf, ')');
        strncpy(nbuf, begin, end - begin);
        nbuf[end-begin] = '\0';
        data_port = atoi(nbuf);
        buf[begin-1-buf] = '\0';
        end = begin - 1;
        begin = strrchr(buf, ',')+1;
        strncpy(nbuf, begin, end - begin);
        nbuf[end-begin] = '\0';
        data_port += 256 * atoi(nbuf);
    }

    return r_code;
}

// 连接到服务器，参数为 IP地址 和 端口号，返回是否连接成功的编号
static int connectToHost(unsigned char* ip, unsigned char* pt)
{
    int sockfd = 0, port = 0;

	port = pt[0]*100 + pt[1];
    if(port <= 0 || port >= 65536)
        errorReport(2);

    server.sin_family = AF_INET;
    server.sin_port   = htons(port);
	server.sin_addr.s_addr =  *(ip+3)<<24 | *(ip+2)<<16 | *(ip+1)<<8 | *(ip+0);

    if((sockfd = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        errorReport(3);
    if(connect(sockfd, (struct sockaddr*)&server, sizeof(server)) < 0)
        errorReport(4);
    
	return sockfd;
}

// 用户登录
static int userLogin(int sockfd)
{
    sendCommand(sockfd, "USER ", user);
    if(getReplyCode(sockfd) == NEED_PASSWORD){
        sendCommand(sockfd, "PASS ", pass);
        if(getReplyCode(sockfd) != LOGIN_SUCS){ //login success!
            return -1;
        }else{
            return 0;
        }
    }else{
        return -1;
    }
}


// 下载服务器的一个文件
static int cmd_get(int fd, char* cmd) 
{
    int i = 0, data_sock, bytes;
	char filename[SZ_256];
	unsigned char buf[BUF_SIZE];
    FILE* dst_file;

	data_port = 0;
    sendCommand(fd, "PASV", "");
    if (getReplyCode(fd) != PASV_MODE){
        return 0;
    }

    server.sin_port = htons(data_port);
    if((data_sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
        errorReport(5);
    if(connect(data_sock, (struct sockaddr*)&server, sizeof(server)) < 0)
        errorReport(6);

    sendCommand(fd, "CWD ", "ODF");
    getReplyCode(fd);
    sendCommand(fd, "CWD ", "410");
    getReplyCode(fd);
    sendCommand(fd, "TYPE ", "I");
    getReplyCode(fd);

	strcpy(filename,cmd);
    sendCommand(fd, "RETR ",filename);

	if(getReplyCode(fd) != DOWN_READY){
        errorReport(7);
        close(fd);
        return 0;
    }

    if((dst_file = fopen(newfilename, "w+b")) == NULL){
        errorReport(8);
        close(fd);
        return 0;
    }

    while((bytes = read(data_sock, buf, BUF_SIZE)) > 0){
        fwrite(buf, 1 , bytes, dst_file);
	}

    close(data_sock);
    getReplyCode(fd);
    fclose(dst_file);

	return 1;
}


// 退出
static void cmd_quit(int fd) 
{
    sendCommand(fd, "QUIT", "");
    if (getReplyCode(fd) == CONTROL_CLOSE){

	}
}

static void split_filename(unsigned char *file,int len)
{
	int i = len;
	
	for(;i > 0;i--){
		if(*(file+i) == 0x5c)
			break;
	}

	memset(newfilename,0,sizeof(newfilename));
	sprintf(newfilename,"/var/yaffs/");
	strncpy(&newfilename[11],&file[0] + i + 1,len-(i-1));
	newfilename[len-i+12] = '\0';

}

// 运行客户端
int run(unsigned char *username,unsigned char *passwd,
		unsigned char* ip, unsigned char* pt,unsigned char *path)
{
	int control_sockfd = 0, rc = 0;

	int filepath_len = *(path+0) <<8 | *(path+1);

	memset(user,0,sizeof(user));
	memset(pass,0,sizeof(pass));
	memset(filepath,0,sizeof(filepath));

	strncpy(user,&username[0]+1,*(username+0));
	strncpy(pass,&passwd[0]+1,*(passwd+0));
	strncpy(filepath,&path[0]+2,filepath_len);
	split_filename(path,filepath_len);

	control_sockfd = connectToHost(ip, pt); 
    if(getReplyCode(control_sockfd) != SERVICE_READY){//220 connect huanying msg
        errorReport(9);
	}

    while(userLogin(control_sockfd) != 0);
   
	rc = cmd_get(control_sockfd,filepath);
	cmd_quit(control_sockfd);
    close(control_sockfd);

	return rc;
}


